#ifndef THREADPOOL_H
#define THREADPOOL_H

#include <condition_variable>
#include <memory>
#include <queue>
#include <thread>
#include <mutex>
#include <functional>
#include <cassert>
#include <utility>

class ThreadPool {
public:
    ThreadPool() = default;
    explicit ThreadPool(size_t threadCount = 8): pool_(std::make_shared<Pool>()){
        assert(threadCount > 0);
        for(size_t i=0; i<threadCount; i++) {
            std::thread([pool = pool_]() {
                std::unique_lock<std::mutex> locker(pool->mtx);
                while(true) {
                    // 任务队列不为空
                    if(!pool->tasks.empty()) {
                        auto task = std::move(pool->tasks.front());
                        pool->tasks.pop();
                        locker.unlock();
                        task();
                        locker.lock();
                    }
                    else if(pool->isClosed) {
                        break;
                    }
                    // 任务队列为空
                    else {
                        // 等待条件变量的通知
                        pool->cond.wait(locker);
                    }
                }
            }).detach();
        }
    }

    ThreadPool(ThreadPool&&) = default;

    ~ThreadPool() {
        // 看它是不是nullptr
        // 如果不是nullptr，说明shared_ptr中还有计数
        if(static_cast<bool>(pool_)) {
            {
                std::lock_guard<std::mutex> locker(pool_->mtx);
                pool_->isClosed = true;
            }
            /*
                notify_all() 是条件变量 pool_->cond 的方法
                用于通知所有正在等待该条件变量的线程
                这是因为在关闭线程池时
                所有线程可能都在等待任务队列变为空
                通过调用 notify_all()
                可以确保所有等待的线程能够被唤醒并继续执行
                从而检查 isClosed 标志并优雅地退出循环。
            */
            pool_->cond.notify_all();
        }
    }

    template<class F>
    void AddTask(F&& task) {
        {
            std::unique_lock<std::mutex> locker(pool_->mtx);
            // 使用完美转发技术，主要是为了避免复制吧？
            pool_->tasks.emplace(std::forward<F>(task));
        }
        pool_->cond.notify_one();
    }

private:
    struct Pool {
        std::mutex mtx;
        std::condition_variable cond;
        bool isClosed;
        std::queue<std::function<void()>> tasks;
    };
    std::shared_ptr<Pool> pool_;
};

#endif // THREADPOOL_H